namespace feng3d
{
    /**
     * Script interface for the Noise Module.
     * 
     * The Noise Module allows you to apply turbulence to the movement of your particles. Use the low quality settings to create computationally efficient Noise, or simulate smoother, richer Noise with the higher quality settings. You can also choose to define the behavior of the Noise individually for each axis.
     * 
     * 噪音模块
     * 
     * 噪音模块允许你将湍流应用到粒子的运动中。使用低质量设置来创建计算效率高的噪音，或者使用高质量设置来模拟更平滑、更丰富的噪音。您还可以选择为每个轴分别定义噪音的行为。
     */
    export class ParticleNoiseModule
    {
        /**
         * Control the noise separately for each axis.
         * 
         * 分别控制每个轴的噪音。
         */
        separateAxes = false;

        /**
         * How strong the overall noise effect is.
         * 
         * 整体噪音效应有多强。
         */
        strength = 1;

        /**
         * Define the strength of the effect on the X axis, when using separateAxes option.
         * 
         * 在使用分别控制每个轴时，在X轴上定义效果的强度。
         */
        strengthX = 1

        /**
         * Define the strength of the effect on the Y axis, when using separateAxes option.
         * 
         * 在使用分别控制每个轴时，在Y轴上定义效果的强度。
         */
        strengthY = 1;

        /**
         * Define the strength of the effect on the Z axis, when using separateAxes option.
         * 
         * 在使用分别控制每个轴时，在Z轴上定义效果的强度。
         */
        strengthZ = 1;

        /**
         * Low values create soft, smooth noise, and high values create rapidly changing noise.
         * 
         * 低值产生柔和、平滑的噪音，高值产生快速变化的噪音。
         */
        frequency = 0.5;

        /**
         * Scroll the noise map over the particle system.
         * 
         * 在粒子系统上滚动噪音图。
         */
        scrollSpeed = 0;

        /**
         * Higher frequency noise will reduce the strength by a proportional amount, if enabled.
         * 
         * 如果启用高频率噪音，将按比例减少强度。
         */
        damping = true;

        /**
         * Layers of noise that combine to produce final noise.
         * 
         * 噪音层数，如果值大于1则最终噪音有多层混合而成。
         */
        octaveCount = 1;

        /**
         * When combining each octave, scale the intensity by this amount.
         * 
         * 多层噪音的混合比率。
         */
        octaveMultiplier = 0.5;

        /**
         * When combining each octave, zoom in by this amount.
         * 
         * 相比第一层的frequency缩放值。
         */
        octaveScale = 2;

        /**
         * Generate 1D, 2D or 3D noise.
         * 
         * 生成一维、二维或三维噪音。
         */
        quality = ParticleSystemNoiseQuality.High;

        /**
         * 噪音
         */
        noise = new feng3d.Noise();

        // 以下两个值用于与Unity中数据接近
        private _frequencyScale = 5;
        private _strengthScale = 4;

        /**
         * 绘制噪音到图片
         * 
         * @param image 图片数据
         */
        drawImage(image: ImageData)
        {
            var frequency = this._frequencyScale * this.frequency;
            var strength = this.strength * this._strengthScale;

            if (this.damping) strength /= this.frequency;

            var data = image.data;

            var imageWidth = image.width;
            var imageHeight = image.height;

            // var datas: number[] = [];
            // var min = Number.MAX_VALUE;
            // var max = Number.MIN_VALUE;

            for (var x = 0; x < imageWidth; x++)
            {
                for (var y = 0; y < imageHeight; y++)
                {
                    var xv = x / imageWidth * frequency;
                    var yv = 1 - y / imageHeight * frequency

                    var value = this._getNoiseValue(xv, yv);

                    // datas.push(value);
                    // if (min > value) min = value;
                    // if (max < value) max = value;

                    value = (value * strength + 1) / 2 * 256;
                    var cell = (x + y * imageWidth) * 4;
                    data[cell] = data[cell + 1] = data[cell + 2] = Math.floor(value);
                    data[cell + 3] = 255; // alpha
                }
            }
            // console.log(datas, min, max);

        }

        /**
         * 获取噪音值
         * 
         * @param x 
         * @param y 
         */
        private _getNoiseValue(x: number, y: number)
        {
            var value = this._getNoiseValueBase(x, y);
            for (var l = 1, ln = this.octaveCount; l < ln; l++)
            {
                var value0 = this._getNoiseValueBase(x * this.octaveScale, y * this.octaveScale);
                value += (value0 - value) * this.octaveMultiplier;
            }
            return value;
        }

        /**
         * 获取单层噪音值
         * 
         * @param x 
         * @param y 
         */
        private _getNoiseValueBase(x: number, y: number)
        {
            var scrollValue = this._scrollValue;
            if (this.quality == ParticleSystemNoiseQuality.Low)
            {
                return this.noise.perlin1(x + scrollValue);
            }
            if (this.quality == ParticleSystemNoiseQuality.Medium)
            {
                return this.noise.perlin2(x, y + scrollValue);
            }
            // if (this.quality == ParticleSystemNoiseQuality.High)
            return this.noise.perlin3(x, y, 0 + scrollValue);
        }

        update()
        {
            var now = Date.now();
            if (Math.abs(now - this._preScrollTime) < 1000)
            {
                this._scrollValue += this.scrollSpeed * (now - this._preScrollTime) / 1000;
            }
            this._preScrollTime = now;
        }

        private _scrollValue = 0;
        private _preScrollTime = 0;
    }

    /**
     * The quality of the generated noise.
     * 
     * 产生的噪音的质量。
     */
    export enum ParticleSystemNoiseQuality
    {
        /**
         * Low quality 1D noise.
         * 
         * 低质量的一维噪音。
         */
        Low,

        /**
         * Medium quality 2D noise.
         * 
         * 中等质量2D噪音。
         */
        Medium,

        /**
         * High quality 3D noise.
         * 
         * 高品质3D噪音。
         */
        High,
    }
}